<?php 
/**
 * This file is part of DomAr.
 * 
 * DomAr is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * DomAr is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with DomAr.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * @link http://inditel.ee/
 * @copyright 2007-2009 Inditel Meedia OÜ
 * @author Oliver Leisalu <oliver@inditel.ee>
 */


/**
* Basic Iterator For handling DomSql queries.
* @package DomAr
* @subpackage Iterator
*/	
class DomArDataIterator extends DomSqlQueryIterator {
	
	/**
	 * @param DomArDataQuery $query
	 * @param String $alias
	 * @return DomArDataIterator
	 */
	public static function c( DomArDataQuery $query, $alias = DomSql::DEFAULT_ALIAS ) {
		return new DomArDataIterator( $query, $alias );
	}
	/**
	 * @param DomArDataQuery $query
	 * @param String $alias
	 */
	public function __construct( DomArDataQuery $query, $alias = DomSql::DEFAULT_ALIAS ) {
		parent::__construct( $query, $alias );
	}

}

/**
* Iterator that converts data to objects.
* @package DomAr
* @subpackage Iterator
*/	
class DomArIterator extends DomSqlQueryIterator {
	
	/**
	 * @var DomArSet
	 */
	protected $list;
	/**
	 * new objects in DomArSet will be added to the end
	 * @var Bool
	 */
	protected $addNewObjects = false;
	/**
	 * These objects are returned in the end of result set. Used by DomArSet in case it contains new objects that are not saved, but set is iterated.
	 * @var Array
	 */
	private $newObjects = array();
	/**
	 * @var Bool
	 */
	protected $loadsMultipleObjects = false;
	/**
	 * This alias is used to determine from which table result object is taken. (Other objects are loaded into memory)
	 * Default is t
	 * @var String
	 */
	protected $mainObjectAlias = 't';
	
	/**
	 * @param DomArQuery $query
	 * @param DomArSet $list
	 * @param String $alias
	 * @return DomArIterator
	 */
	public static function c( DomArQuery $query, DomArSet $list = NULL, $alias = DomSql::DEFAULT_ALIAS ) {
		return new DomArIterator( $query, $list,  $alias );
	}
	/**
	* Constructor
	*
	* @param String/DomSqlQuery $query 
	* @parma DomArSet $list Optional. If added then objects are set to loaded status for that list.
	* @param String $alias
	*/
	public function __construct( DomArQuery $query, DomArSet  $list = NULL, $alias = DomSql::DEFAULT_ALIAS ) {
		parent::__construct( $query, $alias );
		$this->list = $list;
		$this->setLoadsMultipleObjects( $query->loadsMultipleObjects );
		$this->setMainObjectAlias( $query->mainObjectAlias );
	}
	
	protected function parseCurrent() {
		
		/*
		 * This part is used for queries that use joins to load multiple DomArObjects
		 */
		if( $this->loadsMultipleObjects === true ) {
	
			// update current value to main object.
			$data = array();
			foreach( $this->getColumnIndex() as $i => $dat ) {
				$data[$dat['table']][$dat['column']] = &$this->current[$i];
			}
			
			$allObjects = array();
			
			// load all sub objects. They are not actually attached to main object, but cached in memory. When they are needed through main object, they
			// are loaded from memory, so second query is not sent to database.
			foreach( $data as $alias => $dat ) {
				if( $dat['className'] ) {
					$ob = DomAr::getObject( $dat['id'], $dat['className'] );
					if( !$ob ) {
						$ob = call_user_func_array( array($dat['className'],'create'), array(&$dat) );
					}
					$allObjects[$alias] = $ob;
				}
			}
		
			if( $this->mainObjectAlias !== NULL ) {
				$this->current = $allObjects[$this->mainObjectAlias];
				
				if( $this->list ) {
					$this->list->addLoadedObject( $this->current );
				}
				
			} else {
				$this->current = $allObjects;
			}
			
		
		/*
		 * Single object is loaded and deal with it.
		 */
		} else if( !is_object($this->current) && $this->current['className'] ){
		
			$ob = DomAr::getObject( $this->current['id'], $this->current['className'] );
			if( $ob ) {
				$this->current = $ob;
			} else {
				$this->current = call_user_func_array( array($this->current['className'],'create'), array(&$this->current) );
			}
			
			if( $this->list ) {
				$this->list->addLoadedObject( $this->current );
			} 
		}

	}

	public function rewind() {
		parent::rewind();
		
		if( $this->current == NULL && $this->addNewObjects === true ) {
			$this->current = array_shift($this->newObjects);
			if( $this->current )
				$this->parseCurrent();
			
			if( $this->indexColumnName !== NULL )
				$this->currentKey = $this->current->{$this->indexColumnName};
		}
		
		return $this;
	}
	
	public function next() {
		parent::next();
		if( $this->current == NULL && $this->addNewObjects === true) {
			$this->current = array_shift($this->newObjects);
			if( $this->current )
				$this->parseCurrent();
				
			if( $this->indexColumnName !== NULL )
				$this->currentKey = $this->current->{$this->indexColumnName};
		}
		
		return $this->current;
	}
	
	/**
	 * Set properties that are joined and should be handled as sub objects.
	 *
	 * @param array $list
	 */
	public function setLoadsMultipleObjects( $value ) {
		$this->loadsMultipleObjects = (bool)$value;
		$this->setFetchType( $this->loadsMultipleObjects === true ? MYSQL_NUM : MYSQL_ASSOC );
	}
	/**
	 * See property mainObjectAlias
	 * @param String $value
	 */
	public function setMainObjectAlias( $value ) {
		$this->mainObjectAlias = $value;
	}
	/**
	 * If SET has new objects these will be added to the end.
	 * @param Bool $value
	 */
	public function addNewObjects( $value = true ) {
		$this->addNewObjects = (bool)$value;
		if( $this->list ) {
			$this->newObjects = $this->list->getNewObjects();
		}
	}
}
?>